use std::borrow::Cow;

use serde::Serialize;
use thiserror::Error;


pub type IoErr = std::io::Error;
pub type JsonErr = serde_json::Error;

#[derive(Debug, Error)]
pub enum AppErr {
    
    #[error("io:{0}")]
    Io(#[from] IoErr),

    #[error("json:{0}")]
    Json(#[from] JsonErr),

    #[error("http:{0}")]
    Http(#[from] reqwest::Error),

    #[error("custom:{0}")]
    Custom(Cow<'static, str>),
}

impl Serialize for AppErr {

    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: serde::Serializer {
        serializer.serialize_str(&self.to_string())
    }
}

pub trait ErrorConvert<T> {
    
    fn convert(self) -> Result<T, AppErr>;
}

impl <T, E: std::error::Error> ErrorConvert<T> for Result<T, E> {

    fn convert(self) -> Result<T, AppErr> {
        match self {
            Ok(v) => Ok(v),
            Err(e) => Err(AppErr::Custom(Cow::Owned(e.to_string())))
        }
    }
}

impl <T> ErrorConvert<T> for Option<T> {

    fn convert(self) -> Result<T, AppErr> {
        match self {
            Some(v) => Ok(v),
            None => Err(AppErr::Custom(Cow::Borrowed("option is none")))
        }
    }
}
